package org.mybatis.generator.plugin.ext;

import org.mybatis.generator.api.GeneratedXmlFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.ShellCallback;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.XmlConstants;
import org.mybatis.generator.exception.ShellException;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;

/**
 * 生成扩展XML的插件
 * @author 孤傲苍狼
 *
 */
public class ExtMapperXmlGeneratorPlugin extends PluginAdapter {

    private final static String DEFAULT_EXT_XML_PACKAGE = "ext";

    /**
     * 扩展xml文件包名
     */
    private String fullExtXmlPackage;

    /**
     * 利用java反射获取isMergeable参数，并修改
     */
    private java.lang.reflect.Field isMergeableFid = null;

    /**
     * 两个参数用于做数据中转，否则xml文件里会用Base类，这里是为了让xml文件用标准的Model类
     */
    private String modelClassName;
    private String exampleClassName;

    private ShellCallback shellCallback = null;

    public ExtMapperXmlGeneratorPlugin() {
        shellCallback = new DefaultShellCallback(false);

        try {
            if (isMergeableFid == null) {
                isMergeableFid = GeneratedXmlFile.class.getDeclaredField("isMergeable");
                isMergeableFid.setAccessible(true);
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void initialized(IntrospectedTable introspectedTable) {
        // 初始化两参数为空
        modelClassName = null;
        exampleClassName = null;
        modelClassName = introspectedTable.getBaseRecordType();
        introspectedTable.setBaseRecordType(modelClassName);
        exampleClassName = introspectedTable.getExampleType();
        introspectedTable.setExampleType(exampleClassName);
    }

    /*
     * 检查xml参数是否正确
     *
     * @see org.mybatis.generator.api.Plugin#validate(java.util.List)
     */
    @Override
    public boolean validate(List<String> warnings) {
        String xmlTargetPackage = properties.getProperty("xmlTargetPackage");
        if (!stringHasValue(xmlTargetPackage)) {
            return false;
        }

        String extXmlPackage = properties.getProperty("extXmlPackage");
        if (stringHasValue(extXmlPackage)) {
            fullExtXmlPackage = xmlTargetPackage + "." + extXmlPackage;
        } else {
            fullExtXmlPackage = xmlTargetPackage + "." + DEFAULT_EXT_XML_PACKAGE;
        }

        return true;
    }

    /*
   * 生成新的xml文件 ,覆盖原来存在文件
   *
   * @see
   * org.mybatis.generator.api.PluginAdapter#contextGenerateAdditionalXmlFiles
   * (org.mybatis.generator.api.IntrospectedTable)
   */
    @Override
    public List<GeneratedXmlFile> contextGenerateAdditionalXmlFiles(IntrospectedTable introspectedTable) {
        if (modelClassName != null) {
            introspectedTable.setBaseRecordType(modelClassName);
        }

        if (exampleClassName != null) {
            introspectedTable.setExampleType(exampleClassName);
        }

        List<GeneratedXmlFile> extXmlFiles = new ArrayList<GeneratedXmlFile>(1);
        List<GeneratedXmlFile> xmlFiles = introspectedTable.getGeneratedXmlFiles();

        for (GeneratedXmlFile xmlFile : xmlFiles) {
            try {
                // 将xml的isMergeabl改为false
                isMergeableFid.set(xmlFile, false);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

            Document document = new Document(XmlConstants.MYBATIS3_MAPPER_PUBLIC_ID,
                    XmlConstants.MYBATIS3_MAPPER_SYSTEM_ID);
            XmlElement root = new XmlElement("mapper");
            document.setRootElement(root);

            // 生成新的空的xml 但是不覆盖
            root.addAttribute(new Attribute("namespace", introspectedTable.getMyBatis3SqlMapNamespace()));
            root.addElement(new TextElement("<!--"));
            StringBuilder sb = new StringBuilder();
            sb.append("  文件的生成时间： ");
            sb.append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            sb.append('.');
            root.addElement(new TextElement(sb.toString()));
            root.addElement(new TextElement("  把Mapper类的扩展方法的sql语句放在这个文件里面"));

            root.addElement(new TextElement("-->"));
            root.addElement(new TextElement(""));// 添加空白行

            String fileName = xmlFile.getFileName();
            String targetProject = xmlFile.getTargetProject();

            try {
                File directory = shellCallback.getDirectory(targetProject, fullExtXmlPackage);

                File targetFile = new File(directory, fileName);

                if (!targetFile.exists()) {// 需要判断这个xml文件是否存在，若存在则不生成
                    GeneratedXmlFile gxf = new GeneratedXmlFile(document, fileName, fullExtXmlPackage, targetProject,
                            true, context.getXmlFormatter());
                    extXmlFiles.add(gxf);
                }
            } catch (ShellException e) {
                e.printStackTrace();
            }
            extXmlFiles.add(xmlFile);
        }
        return extXmlFiles;
    }

}